// 仓库地址  https://gitee.com/fengliuwt/rust_student.git
// 第5章  使用结构体来组织相关联的数据
/**
   结构，或者说结构体，是一种自定义数据类型，它允许我们命名多个相关的值并将它们组成一个有机的结合体。
   结构体类似于对象中的数据属性。
   1.学习元组与结构体之间的异同
   2.如何定义方法和关联函数 , 它们可以制定那些于结构体数据相关的行为.
  */
// 1.定义并实例化结构体
struct User {
    username:String,
    email:String,
    sign_in_count:u64,
    active:bool,
}
// 我们在结构体定义前添加了#[derive(Debug)]注解，  可以使我们使用println!("{:?}",struct的name ) 打印 struct 结构体
#[derive(Debug)]
struct Rectangle{
    width:u32,
    height:u32,
}


fn main() {
    println!("Hello, world!");
    //创建结构体   如果不带mut关键字   创建的结构体不可改变
    let _user =User{
        email:String::from("123456@163.com"),
        username:String::from("Name_red"),
        sign_in_count:1,
        active:true,
    };
    // 创建带有mut 关键值的结构体 可以改变结构体中属性的值
    // 需要注意的是，一旦实例可变，那么实例中的所有字段都将是可变的。Rust不允许我们单独声明某一部分字段的可变性。
    let mut user_one =User{
        email:String::from("123456@163.com"),
        username:String::from("Name_red"),
        sign_in_count:1,
        active:true,
    };
    user_one.username=String::from("Name_blue");
    println!("{}",user_one.username);

    let user_two= build_user(String::from("23451@123.com"),String::from("Name_black"));
    println!("{}",user_two.username);
    println!("{}",user_two.sign_in_count);
    println!("{}",user_two.email);

    //使用结构体更新语法根据其他实例创建新实例
    let user_three=User{
        username:String::from("Name_pink"),
        email:user_two.email,
        active:user_two.active,
        sign_in_count:user_two.sign_in_count,
    };
    //通过结构体更新语法，我们可以使用更少的代码来实现完全相同的效果，
    let user_four=User{
        username:String::from("Name_pink"),
        email:user_one.email,
        ..user_one
    };
//     使用不需要对字段命名的元组结构体来创建不同的类型
//     定义元组结构体时依然使用struct关键字开头，并由结构体名称及元组中的类型定义组成。
    struct Color(i32,i32,i32);
    struct Point(i32,i32,i32);
    let black=Color(0,0,0);
    let origin=Point(0,0,0);  //注意，这里的black和origin是不同的类型，因为它们两个分别是不同元组结构体的实例


    /**
                                ===================    分割线    =======================
                                下面是第五章    一个使用结构体的示例程序
    */

    let width1=30;
    let height1=50;
    let area=area(width1,height1);
    println!("{}",area);

    //使用元组来重构上面的代码
    let rect1=(30,40);
    let rect2=area_two(rect1);
    println!("{}",rect2);

    // 使用结构体来重构代码：增加有意义的描述信息


    let rect3=Rectangle{
        width:50,
        height:60,
    };
    let rect4=area_three(&rect3);
    println!("{}",rect4);

    //输出结果格式:Rectangle { width: 50, height: 60 }
    println!("rect3 is {:?}",rect3);

    // 可以将println! 字符串中的{:?}替换为{:#?}。
    //输出结果格式:
    // Rectangle {
    //     width: 50,
    //     height: 60,
    // }
    println!("rect3 is {:#?}",rect3);



    //实际上，Rust提供了许多可以通过derive注解来派生的trait，它们可以为自定义的类型增加许多有用的功能










}


fn build_user(email1:String,username1:String)->User{
    User{
        username:username1,
        email:email1,
        sign_in_count:2,
        active:false,
    }

}


//参数与结构体字段拥有完全一致的名称，所以我们可以使用名为字段初始化简写
// （field init shorthand）的语法来重构build_user函数
fn build_user_two(email:String,username:String)->User{
    User{
        username,
        email,
        sign_in_count:2,
        active:false,
    }

}


/**
                            ===================    分割线    =======================
                            下面是第五章    一个使用结构体的示例程序
*/

fn  area(width:u32,height:u32)->u32{
    width*height
}

fn  area_two(dimensions:(u32,u32))->u32{
    dimensions.0*dimensions.1
}

fn  area_three(rectangle:&Rectangle)->u32{
    rectangle.width*rectangle.height
}


/**
                            ===================    分割线    =======================
                            结构体可以让我们基于特定领域创建有意义的自定义类型。通过使用结构体，你可以将相关联的数据组合起来，
                            并为每条数据赋予名字，从而使代码变得更加清晰。方法可以让我们为结构体实例指定行为，
                            而关联函数则可以将那些不需要实例的特定功能放置到结构体的命名空间中。
*/
